<?php
/**
 * 框架核心
 */
namespace framework\core;
use framework\Flight;

class App {
    /**
     * 定义内核版本
     */
    const  VERSION = '1.0.0';
    const  VERSION_DATE = '20160707';

    /**
     * 最低PHP版本要求
     */
    const PHP_REQUIRED = '5.4.0';

    /**
     * 运行框架
     */

    public static function run() {
        self::definitions();
        self::loadConfig();
        self::LoadFile();
        self::DiyRoute();
    }

    /**
     * 定义系统常量
     */
    protected static function definitions() {
        defined('DS') or define('DS',DIRECTORY_SEPARATOR);
        defined('BEGIN_TIME') or define('BEGIN_TIME',microtime(true));
        defined('ROOT_PATH') or define('ROOT_PATH',dirname(__DIR__ ).DS); 
        defined('BASE_PATH') or define('BASE_PATH',ROOT_PATH.'framework'.DS);  
        defined('APP_PATH') or define('APP_PATH',ROOT_PATH.'app'.DS);
        defined('DATA_PATH') or define('DATA_PATH',ROOT_PATH.'data'.DS);
        defined('CONFIG_PATH') or define('CONFIG_PATH',ROOT_PATH.'config'.DS);
        defined('__URL__') or define('__URL__',Flight::request()->base);
        defined('__PUBLIC__') or define('__PUBLIC__', __URL__ . 'public/');
    }

    /**
     * 系统配置
     */
    protected static function loadConfig() {
        //判断PHP版本
        if (version_compare(PHP_VERSION, self::PHP_REQUIRED, '<')) {
            Flight::response(false)->status(404)->write('PHP_VERSION >= '.self::PHP_REQUIRED)->send();
        }
        //加载配置
        Flight::register('config','framework\core\Config');
        Flight::config()->init(ROOT_PATH);
        Flight::config()->loadConfig(CONFIG_PATH.'config.php');
        Flight::config()->loadConfig(CONFIG_PATH.'route.php');
        Flight::set(Flight::config()->get());
        //设置时区
        date_default_timezone_set(Flight::get('TIMEZONE'));
        //是否调试
        if (Flight::get('DEBUG')) {
            ini_set("display_errors", 1);
            error_reporting( E_ALL ^ E_NOTICE );
        } else {
            ini_set("display_errors", 0);
            error_reporting(0);
        }
        if(is_file(APP_PATH.'config.php')){
            Flight::set('APP_CONFIG',include(APP_PATH.'config.php'));
        }
    }

    /**
     * require文件
     */
    protected static function LoadFile() {
        //公共函数
        include(BASE_PATH.'util'.DS.'Function.php');
        //系统函数
        include(BASE_PATH.'util'.DS.'Helper.php');
    }

    /**
     * 根据路由加载控制器和方法
     */
    protected static function DiyRoute() {
        /**
         * DIY路由规则
         * 配置规则 '/hello(/@name)' =>'APP/控制器/方法',
         * 默认URL路径 /
         * HTTP METHOD路由: GET|POST /
         * 正则表达式 /user/[0-9]+
         * 命名参数: /@name/@id
         * 命名参数&正则表达式: /@name/@id:[0-9]{3}
         */
        $_CFG_ROUTE = Flight::get('ROUTE');
        foreach ($_CFG_ROUTE as $key => $value ){
            Flight::route($key,function()use($value) {
                list($app,$controller,$action) = explode('/', $value);
                $app        = strtolower($app);
                $controller = ucfirst(strtolower($controller));
                $action     = $action;
                $controller_class = "\\app\\{$app}\\controller\\{$controller}Controller";
                self::DefinedRoute($app,$controller,$action,$controller_class);
                $callback = array(new $controller_class,$action);
                call_user_func_array($callback,func_get_args());
            },true);
        };
        /**
         * 配置通用路由
         * 基于传递参数的方式的考虑没有采用反射实现。
         * 支持以“/APP/控制器/方法/参数”形势的路由访问
         */
        Flight::route('/@app/@controller/@action',function (){
            $params     = func_get_args();
            $app        = strtolower(array_shift($params));
            $controller = ucfirst(strtolower(array_shift($params)));
            $action     = array_shift($params);
            $route_obj  = array_shift($params);
            $params = explode('/', $route_obj->splat);
            $controller_class = "\\app\\{$app}\\controller\\{$controller}Controller";
            self::DefinedRoute($app,$controller,$action,$controller_class);
            $callback = array(new $controller_class(),$action);
            call_user_func_array($callback,$params);
        },true);
    }

    /**
     * 定义路由常量
     */
    protected static function DefinedRoute($app,$controller,$action,$controller_class) {
        if(!class_exists($controller_class) ) {
            if (Flight::get('DEBUG')) {
                throw new \Exception("The Controller '{$controller_class}' not found", 500);
            }else{
                Flight::notFound();
            }
        }
        if (!is_callable(array($controller_class,$action))){
            if (Flight::get('DEBUG')) {
                throw new \Exception("The '{$controller_class}::{$action}()' not found");
            }else{
                Flight::notFound();
            }
        }
        defined('APP_NAME') or define('APP_NAME',strtolower($app));
        defined('CONTROLLER_NAME') or define('CONTROLLER_NAME',strtolower($controller));
        defined('ACTION_NAME') or define('ACTION_NAME',strtolower($action));
        defined('APP_ROUTE') or define('APP_ROUTE',strtolower($app.'/'.$controller.'/'.$action));
        //APP私有配置和私有函数
        $config   = APP_PATH.APP_NAME.DS.'config.php';
        $function = APP_PATH.APP_NAME.DS.'function.php';
        if(is_file($config)){
            Flight::set(strtoupper(APP_NAME),include($config));
        }
        if(is_file($function)){
            include($function);
        }
    }
}